package com.atguigu.lease.web.admin.service.impl;

import com.atguigu.lease.common.exception.LeaseException;
import com.atguigu.lease.common.result.ResultCodeEnum;
import com.atguigu.lease.model.entity.*;
import com.atguigu.lease.model.enums.ItemType;
import com.atguigu.lease.model.enums.ReleaseStatus;
import com.atguigu.lease.web.admin.mapper.ApartmentInfoMapper;
import com.atguigu.lease.web.admin.service.*;
import com.atguigu.lease.web.admin.vo.apartment.ApartmentDetailVo;
import com.atguigu.lease.web.admin.vo.apartment.ApartmentItemVo;
import com.atguigu.lease.web.admin.vo.apartment.ApartmentQueryVo;
import com.atguigu.lease.web.admin.vo.apartment.ApartmentSubmitVo;
import com.atguigu.lease.web.admin.vo.fee.FeeValueVo;
import com.atguigu.lease.web.admin.vo.graph.GraphVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author liubo
 * @description 针对表【apartment_info(公寓信息表)】的数据库操作Service实现
 * @createDate 2023-07-24 15:48:00
 */
@Service
@Transactional
public class ApartmentInfoServiceImpl extends ServiceImpl<ApartmentInfoMapper, ApartmentInfo>
        implements ApartmentInfoService {

    @Autowired
    private ApartmentFacilityService apartmentFacilityService;

    @Autowired
    private ApartmentFeeValueService apartmentFeeValueService;

    @Autowired
    private ApartmentLabelService apartmentLabelService;

    @Autowired
    private GraphInfoService graphInfoService;

    @Autowired
    private ApartmentInfoMapper apartmentInfoMapper;

    @Autowired
    private LabelInfoService labelInfoService;

    @Autowired
    private FeeValueService feeValueService;

    @Autowired
    private RoomInfoService roomInfoService;


    @Override
    public void saveOrUpdateApartment(ApartmentSubmitVo apartmentSubmitVo) {

        Long apartmentId0 = apartmentSubmitVo.getId();

        boolean updateFlag = apartmentId0 != null && apartmentId0 != 0;

        // 1.保存或更新ApartmentInfo自身的信息（insert或update apartmentInfo表）
        super.saveOrUpdate(apartmentSubmitVo);


        // 2.如果是更新，则需要先删除掉之前的关系信息
        if (updateFlag) {
            // 2-1.删除和配套之间的关系
            /*
            apartmentSubmitVo.getFacilityInfoIds().forEach(facilityId ->{
                apartmentFacilityService.remove(new LambdaQueryWrapper<ApartmentFacility>()
                        .eq(ApartmentFacility::getApartmentId, apartmentId));
            });
            */
            apartmentFacilityService.remove(new LambdaQueryWrapper<ApartmentFacility>()
                    .eq(ApartmentFacility::getApartmentId, apartmentId0));
            // 2-2.删除和标签之间的关系
            apartmentLabelService.remove(new LambdaQueryWrapper<ApartmentLabel>()
                    .eq(ApartmentLabel::getLabelId, apartmentId0));
            // 2-3.删除和杂费之间的关系
            apartmentFeeValueService.remove(new LambdaQueryWrapper<ApartmentFeeValue>()
                    .eq(ApartmentFeeValue::getApartmentId, apartmentId0));
            // 2-4.删除之前的图片
            graphInfoService.remove(new LambdaQueryWrapper<GraphInfo>()
                    .eq(GraphInfo::getItemId, apartmentId0)
                    .eq(GraphInfo::getItemType, ItemType.APARTMENT));

        }

        // 3.保存公寓的关系信息（和配套的关系，和杂费的关系，和标签的关系，和图片的关系）

        Long apartmentId = apartmentSubmitVo.getId();

        // 3-1.保存和配套的关系信息
        apartmentSubmitVo.getFacilityInfoIds().stream().map(facilityId -> new ApartmentFacility(apartmentId, facilityId))
                .forEach(apartmentFacilityService::saveOrUpdate);

        // 3-2.保存和杂费的配套信息
        apartmentSubmitVo.getFeeValueIds().stream().map(feeValueId -> new ApartmentFeeValue(apartmentId, feeValueId))
                .forEach(apartmentFeeValueService::saveOrUpdate);

        // 3-3.保存和标签的关系信息
        apartmentSubmitVo.getLabelIds().stream().map(labelId -> ApartmentLabel.builder().apartmentId(apartmentId).labelId(labelId).build())
                .forEach(apartmentLabelService::saveOrUpdate);

        // 3-4.保存图片信息

        /*
        // 方式一
        List<GraphInfo> graphInfoList = new ArrayList<>();
        apartmentSubmitVo.getGraphVoList().forEach(graphVo -> {
            GraphInfo graphInfo = new GraphInfo();
            BeanUtils.copyProperties(graphVo, graphInfo);
            graphInfo.setItemType(ItemType.APARTMENT);
            graphInfo.setItemId(apartmentId);

            graphInfoList.add(graphInfo);
        });
        graphInfoService.saveOrUpdateBatch(graphInfoList);
         */

        /*
        // 方式二
        graphInfoService.saveOrUpdateBatch(
            apartmentSubmitVo.getGraphVoList().stream().map(graphVo -> {
                GraphInfo graphInfo = new GraphInfo();
                BeanUtils.copyProperties(graphVo, graphInfo);
                graphInfo.setItemType(ItemType.APARTMENT);
                graphInfo.setItemId(apartmentId);
                return graphInfo;
            }).collect(Collectors.toList())
        );
         */

        // 方式三(在GraphInfo加入@Builder)
        graphInfoService.saveOrUpdateBatch(
                apartmentSubmitVo.getGraphVoList().stream().map(graphVo ->
                    GraphInfo.builder()
                            .name(graphVo.getName())
                            .url(graphVo.getUrl())
                            .itemType(ItemType.APARTMENT)
                            .itemId(apartmentId)
                            .build()
                ).collect(Collectors.toList())
        );
    }

    @Override
    public void pageApartmentItemByQuery(IPage<ApartmentItemVo> page, ApartmentQueryVo queryVo) {
        apartmentInfoMapper.pageApartmentItemByQuery(page, queryVo);
    }

    @Override
    public ApartmentDetailVo getApartmentDetail(Long apartmentId) {
        // 业务方法：获取公寓详情，应该包含如下五个动作：
        // 1、获取公寓基本信息
        ApartmentInfo apartmentInfo = getById(apartmentId);
        if (apartmentInfo != null) {
            // 2、获取公寓配套信息
            List<FacilityInfo> facilityList = apartmentFacilityService.getApartmentFacilityListByApartmentId(apartmentId);
            // 3、获取公寓标签信息
            List<LabelInfo> labelInfoList = labelInfoService.getLabelInfoListByApartmentId(apartmentId);
            // 4、获取公寓杂费信息
            List<FeeValueVo> feeValueList = feeValueService.getFeeValueListByApartmentId(apartmentId);
            // 5、获取公寓图片信息
            List<GraphInfo> graphInfoList = graphInfoService.list(new LambdaQueryWrapper<GraphInfo>().eq(GraphInfo::getItemType, ItemType.APARTMENT).eq(GraphInfo::getItemId, apartmentId));

            ApartmentDetailVo apartmentDetailVo = new ApartmentDetailVo();
            BeanUtils.copyProperties(apartmentInfo, apartmentDetailVo);
            apartmentDetailVo.setFacilityInfoList(facilityList);
            apartmentDetailVo.setLabelInfoList(labelInfoList);
            apartmentDetailVo.setFeeValueVoList(feeValueList);
            apartmentDetailVo.setGraphVoList(graphInfoList.stream().map(graphInfo -> GraphVo.builder().name(graphInfo.getName()).url(graphInfo.getUrl()).build()).toList());

            return apartmentDetailVo;
        }
        return null;
    }

    @Override
    public void removeApartmentById(Long id) {

        // 如果待删除的公寓信息有房间信息，则不允许删除，直接给前端报207错误
        if (roomInfoService.count(new LambdaQueryWrapper<RoomInfo>().eq(RoomInfo::getApartmentId, id)) > 0){
            // 此处抛异常，会被全局异常处理捕获
            throw new LeaseException(ResultCodeEnum.DELETE_ERROR);
        }

        // 删除公寓本身的信息
        super.removeById(id);

        // 删除公寓关联的信息：配套、标签、杂费、图片
        // 1、配套：删除的是中间关系表的记录，不是删除配套表里面的信息
        apartmentFacilityService.remove(new LambdaQueryWrapper<ApartmentFacility>().eq(ApartmentFacility::getApartmentId, id));

        // 2、标签
        apartmentLabelService.remove(new LambdaQueryWrapper<ApartmentLabel>().eq(ApartmentLabel::getApartmentId, id));

        // 3、杂费
        apartmentFeeValueService.remove(new LambdaQueryWrapper<ApartmentFeeValue>().eq(ApartmentFeeValue::getApartmentId, id));

        // 4、图片
        graphInfoService.remove(new LambdaQueryWrapper<GraphInfo>().eq(GraphInfo::getItemType, ItemType.APARTMENT).eq(GraphInfo::getItemId, id));
    }

    @Override
    public void updateStatus(Long id, ReleaseStatus status) {
        super.update(new LambdaUpdateWrapper<ApartmentInfo>().eq(ApartmentInfo::getId, id).set(ApartmentInfo::getIsRelease, status));
    }
}




